home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-04-15 | 6.2 KB | 259 lines | [TEXT/MMCC] |
- // AEThreads.h
- //
- // Copyright © 1993-95 Steve Sisak
- //
- // License is granted to use, modify, make derivative works, and
- // duplicate this code at will, so long as this notice remains intact.
- //
-
- #ifndef __AETHREADS__
- #include "AEThreads.h"
- #endif
- #ifndef __ERRORS__
- #include <Errors.h>
- #endif
- #ifndef __APPLEEVENTS__
- #include <AppleEvents.h>
- #endif
- #if __MWERKS__
- #if defined(powerc) || defined(__powerc)
- #include <CPlusLibPPC.h>
- #else
- #include <stdlib.h>
- #include <CPlusLib68k.h>
- #endif
- #endif
-
- typedef struct AEThreadDesc AEThreadDesc;
- typedef struct AEThreadParam AEThreadParam;
- typedef struct AESwapData AESwapData;
-
- // A pointer to this structure is kept in the refcon stored by
- // AEInstallEventHandler(). Since they are typically only created at
- // application startup time, using a pointer will not fragment the
- // application heap.
-
- struct AEThreadDesc // Kept in the OS refcon
- {
- AEEventHandlerUPP handler; // The real handler
- long refcon; // The real refcon
- Size stackSize; // Stack size for handling event
- ThreadOptions options; // Thread options for event
- ThreadID holder; // used as a semaphore
- };
-
- // This structure is used to pass parameters to a new thread during the
- // spawning process. Note that it is passed on the stack and must be
- // kept valid until the thread has run once.
-
- struct AEThreadParam // Used in spawning
- {
- const AppleEvent* event;
- AppleEvent* reply;
- AEThreadDesc* desc;
- ThreadID thread;
- OSErr result;
- };
-
- // This structure is used to store any thread context which must be
- // saved snd restored as the thread is swapped in and out. You may
- // want to modify this structure and AESwitchInHandler() and
- // AESwitchOutHandler() to save more context. In the future, this
- // should really be a C++ class
-
- struct AESwapData
- {
- void* fTopHandler; // Top failure handler
-
- #ifdef __MWERKS__
- DestructorChain* fStaticChain; //
- #endif
- };
-
- pascal void AESwitchInHandler(ThreadID threadBeingSwitched, void *switchProcParam);
- pascal void AESwitchOutHandler(ThreadID threadBeingSwitched, void *switchProcParam);
- pascal OSErr AESpawnAEThread(const AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon);
- pascal long AEThread(AEThreadParam* parms);
-
- AEEventHandlerUPP gSpawnAEThreadUPP = nil;
-
- #pragma segment foobar
-
- pascal OSErr AEInstallThreadedEventHandler(
- AEEventClass theAEEventClass,
- AEEventID theAEEventID,
- AEEventHandlerUPP proc,
- long handlerRefcon,
- ThreadOptions options,
- Size stacksize)
- {
- AEThreadDesc* desc = (AEThreadDesc*) NewPtr(sizeof(AEThreadDesc));
- OSErr err = MemError();
-
- if (gSpawnAEThreadUPP == nil)
- {
- gSpawnAEThreadUPP = NewAEEventHandlerProc(AESpawnAEThread);
- }
-
- if (err == noErr)
- {
- desc->handler = proc;
- desc->refcon = handlerRefcon;
- desc->stackSize = stacksize;
- desc->options = options;
- desc->holder = kNoThreadID;
-
- err = AEInstallEventHandler(theAEEventClass, theAEEventID, gSpawnAEThreadUPP, (long) desc, false);
- }
-
- return err;
- }
-
- #pragma segment AEThread
-
- pascal void AESwitchInHandler(ThreadID threadBeingSwitched, void *switchProcParam)
- {
- AESwapData* swap = (AESwapData*) switchProcParam;
-
- #ifdef __MWERKS__
- swap->fStaticChain = __local_destructor_chain;
- #endif
-
- // Swap in any additional context here
-
- }
-
- pascal void AESwitchOutHandler(ThreadID threadBeingSwitched, void *switchProcParam)
- {
- AESwapData* swap = (AESwapData*) switchProcParam;
-
- // Swap out any additional context here
-
- #ifdef __MWERKS__
- __local_destructor_chain = swap->fStaticChain;
- #endif
- }
-
-
- #define ErrCheck(label, result) if ((result) != noErr) goto label;
-
- pascal long AEThread(AEThreadParam* parms)
- {
- AppleEvent event; // Original parameters we care about
- AppleEvent reply;
- AEThreadDesc* desc;
- OSErr err;
- OSErr procErr;
- AESwapData swap;
-
- event = *parms->event; // copy these into our own stack frame
- reply = *parms->reply;
- desc = parms->desc;
-
- #if 0
- myTopHandler = gTopHandler; // Save global failure handler
- gTopHandler = nil; // don't let failures propagate outside
- #endif
-
- ErrCheck(punt, err = SetThreadSwitcher(kCurrentThreadID, AESwitchInHandler, &swap, true));
- ErrCheck(punt, err = SetThreadSwitcher(kCurrentThreadID, AESwitchOutHandler, &swap, false));
- ErrCheck(punt, err = AESuspendTheCurrentEvent(&event));
-
- parms->result = noErr; // Let caller know we're ready
-
- // At this point, we need to let our caller return
-
- while (desc->holder != kNoThreadID)
- {
- YieldToThread(desc->holder);
- }
-
- // We are now on our own
-
- procErr = err = CallAEEventHandlerProc(desc->handler, &event, &reply, desc->refcon);
-
- // Since the event was suspended, we need to stuff the error code ourselves
- // note that there's not much we can do about reporting errors beyond here
-
- err = AEPutAttributePtr(&reply, keyErrorNumber, typeShortInteger, &procErr, sizeof(procErr));
-
- #if qDebug
- if (err)
- ProgramBreak("\pAEPutAttributePtr failed installing error code - very bad");
- #endif
-
- err = AEResumeTheCurrentEvent(&event, &reply, kAENoDispatch, 0); // This had better work
-
- #if qDebug
- if (err)
- DebugStr("\pAEResumeTheCurrentEvent failed - very bad");
- #endif
-
- #if 0
- gTopHandler = myTopHandler; // Restore global failure handler
- myTopHandler = nil; // Keep terminator from firing handlers
- #endif
-
- punt:
- parms->result = err;
- return nil;
- }
-
- #pragma segment Spawn
-
- pascal OSErr AESpawnAEThread(const AppleEvent *event, AppleEvent *reply, long handlerRefcon)
- {
- AEThreadParam param;
-
- param.event = event;
- param.reply = reply;
- param.desc = (AEThreadDesc*) handlerRefcon;
- param.thread = kNoThreadID;
-
- if (!param.desc)
- {
- param.result = paramErr;
- }
- else
- {
- // make sure no-one else is trying to start a handler
-
- while (param.desc->holder != kNoThreadID)
- {
- YieldToAnyThread();
- }
-
- // Grab the semaphore
-
- if ((param.result = GetCurrentThread(¶m.desc->holder)) == noErr)
- {
- param.result = NewThread(kCooperativeThread,
- (ThreadEntryProcPtr) &AEThread,
- ¶m,
- param.desc->stackSize,
- param.desc->options,
- nil,
- ¶m.thread);
-
- if (param.result == noErr)
- {
- param.result = 1;
-
- do
- {
- YieldToThread(param.thread);
- }
- while (param.result == 1); // Wait for thread to pick up parameters
- }
- }
-
- param.desc->holder = kNoThreadID; // release any claims we have
- }
-
- return param.result;
- }
-
-
-
-
-